﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.ComponentModel.Composition;

using NuMetaheuristics;
using NuMetaheuristics.Genotypes;
using NuMetaheuristics.Operators.Value;

namespace NuMetaheuristics.Operators.Vector
{
    /// <summary>
    /// Multiply each element in vector by a given scalar.
    /// </summary>
    [Export(typeof(IUnaryOperator<DoubleVectorGenotype>))]
    [DataContract(Namespace = "http://numetaheuristics.codeplex.com/schemas")]
    public class DoubleVectorScalarMultiplier : IUnaryOperator<DoubleVectorGenotype>
    {
        [DataMember]
        private double _scalar;

        public DoubleVectorScalarMultiplier()
        {
        }

        public DoubleVectorScalarMultiplier(double scalar)
        {
            _scalar = scalar;
        }

        public void Operate(ref DoubleVectorGenotype operand)
        {
            if (operand == null)
                throw new ArgumentNullException();

            for (int i = 0; i < operand.Vector.Length; i++)
            {
                operand.Vector[i] = _scalar * operand.Vector[i];
            }
        }
    }

    /// <summary>
    /// /// Multiply each element in vector by a given scalar.
    /// </summary>
    [Export(typeof(IUnaryOperator<DoubleVectorGenotype>))]
    [DataContract(Namespace = "http://numetaheuristics.codeplex.com/schemas")]
    public class RandomDoubleVectorScalarMultiplier : IUnaryOperator<DoubleVectorGenotype>
    {
        [DataMember]
        private DoubleRandomInitializer _randomInitializer;

        public RandomDoubleVectorScalarMultiplier()
        {
        }

        public RandomDoubleVectorScalarMultiplier(DoubleRandomInitializer randomInitializer)
        {
            _randomInitializer = randomInitializer;
        }

        public void Operate(ref DoubleVectorGenotype operand)
        {
            if (operand == null)
                throw new ArgumentNullException();

            if (_randomInitializer == null)
                throw new NullReferenceException();

            for (int i = 0; i < operand.Vector.Length; i++)
            {
                double scalar = 0.0;
                _randomInitializer.Operate(ref scalar);

                operand.Vector[i] = scalar * operand.Vector[i];
            }
        }
    }

    /// <summary>
    /// Multiply each element in a vector by a random scalar. The random 
    /// scalar is determined by the given random initalizer.
    /// </summary>
    [Export(typeof(IUnaryOperator<IntegerVectorGenotype>))]
    [DataContract(Namespace = "http://numetaheuristics.codeplex.com/schemas")]
    public class IntegerVectorScalarMultiplier : IUnaryOperator<IntegerVectorGenotype>
    {
        [DataMember]
        private int _scalar;

        public IntegerVectorScalarMultiplier()
        {
        }

        public IntegerVectorScalarMultiplier(int scalar)
        {
            _scalar = scalar;
        }

        public void Operate(ref IntegerVectorGenotype operand)
        {
            if (operand == null)
                throw new ArgumentNullException();

            for (int i = 0; i < operand.Vector.Length; i++)
            {
                operand.Vector[i] = _scalar * operand.Vector[i];
            }
        }
    }

    /// <summary>
    /// Multiply each element in a vector by a random scalar. The random 
    /// scalar is determined by the given random initalizer.
    /// </summary>
    [Export(typeof(IUnaryOperator<IntegerVectorGenotype>))]
    [DataContract(Namespace = "http://numetaheuristics.codeplex.com/schemas")]
    public class RandomIntegerVectorScalarMultiplier : IUnaryOperator<IntegerVectorGenotype>
    {
        [DataMember]
        private IntegerRandomInitializer _randomInitializer;

        public RandomIntegerVectorScalarMultiplier()
        {
        }

        public RandomIntegerVectorScalarMultiplier(IntegerRandomInitializer randomInitializer)
        {
            _randomInitializer = randomInitializer;
        }

        public void Operate(ref IntegerVectorGenotype operand)
        {
            if (operand == null)
                throw new ArgumentNullException();

            if (_randomInitializer == null)
                throw new NullReferenceException();

            for (int i = 0; i < operand.Vector.Length; i++)
            {
                int scalar = 0;
                _randomInitializer.Operate(ref scalar);

                operand.Vector[i] = scalar * operand.Vector[i];
            }
        }
    }
}
